#!/usr/bin/env python
"""
缓存清理脚本
用于清空各种类型的缓存，包括Django缓存、Redis缓存、Session缓存等
"""

import os
import sys
import django
import redis
import logging
from datetime import datetime

# 添加Django项目路径
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fs_admin.settings')

# 初始化Django
django.setup()

from django.core.cache import cache, caches
from django.core.management import call_command
from django.conf import settings
from django.contrib.sessions.models import Session
from django.http import HttpResponse

# 确保logs目录存在
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
LOGS_DIR = os.path.join(BASE_DIR, 'logs')
os.makedirs(LOGS_DIR, exist_ok=True)

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(),
        logging.FileHandler(os.path.join(LOGS_DIR, 'cache_clear.log'))
    ]
)
logger = logging.getLogger(__name__)


class CacheCleaner:
    """缓存清理器"""
    
    def __init__(self):
        self.results = {
            'django_cache': False,
            'redis_cache': False,
            'session_cache': False,
            'method_decorator_cache': False,
            'database_sessions': False,
            'browser_cache_headers': False
        }
    
    def clear_django_cache(self):
        """清空Django默认缓存"""
        try:
            cache.clear()
            logger.info("✅ Django默认缓存已清空")
            self.results['django_cache'] = True
            return True
        except Exception as e:
            logger.error(f"❌ 清空Django缓存失败: {str(e)}")
            return False
    
    def clear_all_django_caches(self):
        """清空所有Django缓存别名"""
        try:
            cache_aliases = getattr(settings, 'CACHES', {}).keys()
            for alias in cache_aliases:
                try:
                    cache_instance = caches[alias]
                    cache_instance.clear()
                    logger.info(f"✅ Django缓存 '{alias}' 已清空")
                except Exception as e:
                    logger.error(f"❌ 清空Django缓存 '{alias}' 失败: {str(e)}")
            
            self.results['django_cache'] = True
            return True
        except Exception as e:
            logger.error(f"❌ 清空Django所有缓存失败: {str(e)}")
            return False
    
    def clear_redis_cache(self):
        """直接清空Redis缓存"""
        try:
            # 从settings获取Redis配置
            redis_configs = []
            
            if hasattr(settings, 'CACHES'):
                for cache_name, cache_config in settings.CACHES.items():
                    if 'redis' in cache_config.get('BACKEND', '').lower():
                        location = cache_config.get('LOCATION', '')
                        if location:
                            redis_configs.append((cache_name, location))
            
            if not redis_configs:
                # 默认Redis配置
                redis_configs = [
                    ('default', 'redis://127.0.0.1:6379/0'),
                    ('session', 'redis://127.0.0.1:6379/1')
                ]
            
            for cache_name, location in redis_configs:
                try:
                    # 解析Redis连接信息
                    if location.startswith('redis://'):
                        # 格式: redis://host:port/db
                        location = location[8:]  # 移除 'redis://'
                        if '/' in location:
                            host_port, db = location.rsplit('/', 1)
                            db = int(db)
                        else:
                            host_port = location
                            db = 0
                        
                        if ':' in host_port:
                            host, port = host_port.split(':')
                            port = int(port)
                        else:
                            host = host_port
                            port = 6379
                    else:
                        host, port, db = '127.0.0.1', 6379, 0
                    
                    # 连接Redis并清空
                    r = redis.Redis(host=host, port=port, db=db, decode_responses=True)
                    r.flushdb()
                    logger.info(f"✅ Redis缓存 '{cache_name}' ({host}:{port}/{db}) 已清空")
                    
                except Exception as e:
                    logger.error(f"❌ 清空Redis缓存 '{cache_name}' 失败: {str(e)}")
            
            self.results['redis_cache'] = True
            return True
            
        except Exception as e:
            logger.error(f"❌ Redis缓存清理失败: {str(e)}")
            return False
    
    def clear_session_cache(self):
        """清空Session缓存"""
        try:
            # 清空基于缓存的session
            if hasattr(settings, 'SESSION_ENGINE') and 'cache' in settings.SESSION_ENGINE:
                session_cache_alias = getattr(settings, 'SESSION_CACHE_ALIAS', 'default')
                session_cache = caches[session_cache_alias]
                session_cache.clear()
                logger.info(f"✅ Session缓存 (别名: {session_cache_alias}) 已清空")
            
            # 清空数据库中的session记录
            try:
                deleted_count = Session.objects.all().delete()[0]
                logger.info(f"✅ 数据库Session记录已清空 ({deleted_count} 条记录)")
                self.results['database_sessions'] = True
            except Exception as e:
                logger.warning(f"⚠️ 清空数据库Session记录失败: {str(e)}")
            
            self.results['session_cache'] = True
            return True
            
        except Exception as e:
            logger.error(f"❌ Session缓存清理失败: {str(e)}")
            return False
    
    def clear_method_decorator_cache(self):
        """清空@method_decorator装饰器缓存"""
        try:
            # Django的@method_decorator(cache_page(...))使用的是默认缓存
            # 已经在clear_django_cache中处理
            
            # 如果使用了lru_cache，需要手动清理
            # 这里提供一个示例，实际需要根据项目中的具体使用情况调整
            import importlib
            
            # 尝试清理可能使用了lru_cache的模块
            modules_to_clear = [
                'opration.utils',  # 从搜索结果看到这个模块使用了@lru_cache
                # 可以根据需要添加更多模块
            ]
            
            for module_name in modules_to_clear:
                try:
                    module = importlib.import_module(module_name)
                    # 查找模块中所有使用lru_cache的函数
                    for attr_name in dir(module):
                        attr = getattr(module, attr_name)
                        if hasattr(attr, 'cache_clear'):  # lru_cache装饰的函数有cache_clear方法
                            attr.cache_clear()
                            logger.info(f"✅ 清空了 {module_name}.{attr_name} 的lru_cache")
                except Exception as e:
                    logger.warning(f"⚠️ 清空模块 {module_name} lru_cache失败: {str(e)}")
            
            self.results['method_decorator_cache'] = True
            return True
            
        except Exception as e:
            logger.error(f"❌ @method_decorator缓存清理失败: {str(e)}")
            return False
    
    def generate_browser_cache_clear_headers(self):
        """生成清空浏览器缓存的HTTP响应头"""
        try:
            headers = {
                'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0',
                'Pragma': 'no-cache',
                'Expires': '0',
                'Last-Modified': datetime.now().strftime('%a, %d %b %Y %H:%M:%S GMT'),
                'ETag': f'"{int(datetime.now().timestamp())}"'
            }
            
            logger.info("✅ 浏览器缓存清理响应头已生成:")
            for header, value in headers.items():
                logger.info(f"   {header}: {value}")
            
            # 保存到文件供参考
            browser_cache_file = os.path.join(LOGS_DIR, 'browser_cache_headers.log')
            with open(browser_cache_file, 'w', encoding='utf-8') as f:
                f.write("# 在Django视图中添加以下响应头来清空浏览器缓存:\n")
                f.write("# 方法1: 在视图函数中\n")
                f.write("response = HttpResponse()\n")
                for header, value in headers.items():
                    f.write(f"response['{header}'] = '{value}'\n")
                
                f.write("\n# 方法2: 使用装饰器\n")
                f.write("from django.views.decorators.cache import never_cache\n")
                f.write("@never_cache\n")
                f.write("def your_view(request):\n")
                f.write("    # your view logic\n")
                f.write("    pass\n")
                
                f.write("\n# 方法3: 在中间件中全局设置\n")
                f.write("# 在response中添加上述响应头\n")
            
            logger.info(f"✅ 浏览器缓存清理说明已保存到 {browser_cache_file}")
            self.results['browser_cache_headers'] = True
            return True
            
        except Exception as e:
            logger.error(f"❌ 生成浏览器缓存清理响应头失败: {str(e)}")
            return False
    
    def clear_opcache(self):
        """清空PHP OPcache (如果适用)"""
        try:
            # 对于Python项目，这通常不适用
            # 但如果项目中有PHP组件，可以尝试
            logger.info("ℹ️ Python项目无需清空PHP OPcache")
            return True
        except Exception as e:
            logger.error(f"❌ OPcache清理失败: {str(e)}")
            return False
    
    def clear_all_caches(self):
        """清空所有缓存"""
        logger.info("🚀 开始清空所有缓存...")
        logger.info("=" * 50)
        
        # 1. 清空Django缓存
        logger.info("1. 清空Django缓存")
        self.clear_all_django_caches()
        
        # 2. 清空Redis缓存
        logger.info("\n2. 清空Redis缓存")
        self.clear_redis_cache()
        
        # 3. 清空Session缓存
        logger.info("\n3. 清空Session缓存")
        self.clear_session_cache()
        
        # 4. 清空装饰器缓存
        logger.info("\n4. 清空@method_decorator缓存")
        self.clear_method_decorator_cache()
        
        # 5. 生成浏览器缓存清理响应头
        logger.info("\n5. 生成浏览器缓存清理响应头")
        self.generate_browser_cache_clear_headers()
        
        logger.info("\n" + "=" * 50)
        logger.info("🎉 缓存清理完成!")
        
        # 显示结果摘要
        self.show_summary()
    
    def show_summary(self):
        """显示清理结果摘要"""
        logger.info("\n📊 清理结果摘要:")
        logger.info("-" * 30)
        
        success_count = sum(self.results.values())
        total_count = len(self.results)
        
        for task, success in self.results.items():
            status = "✅ 成功" if success else "❌ 失败"
            logger.info(f"{task}: {status}")
        
        logger.info(f"\n总计: {success_count}/{total_count} 项成功")
        
        # 额外建议
        logger.info("\n💡 额外建议:")
        logger.info("- 重启Django应用服务器以确保所有缓存完全清空")
        logger.info("- 在浏览器中按 Ctrl+F5 (Windows) 或 Cmd+Shift+R (Mac) 强制刷新")


def main():
    """主函数"""
    try:
        cleaner = CacheCleaner()
        
        # 检查命令行参数
        if len(sys.argv) > 1:
            action = sys.argv[1]
            if action == 'django':
                cleaner.clear_all_django_caches()
            elif action == 'redis':
                cleaner.clear_redis_cache()
            elif action == 'session':
                cleaner.clear_session_cache()
            elif action == 'decorator':
                cleaner.clear_method_decorator_cache()
            elif action == 'browser':
                cleaner.generate_browser_cache_clear_headers()
            else:
                print("使用方法:")
                print("python clear_cache.py [django|redis|session|decorator|browser]")
                print("或者不带参数清空所有缓存")
                return
        else:
            # 清空所有缓存
            cleaner.clear_all_caches()
            
    except KeyboardInterrupt:
        logger.info("\n⚠️ 用户中断了缓存清理操作")
    except Exception as e:
        logger.error(f"❌ 缓存清理过程中发生错误: {str(e)}")
        sys.exit(1)


if __name__ == '__main__':
    main() 